from myAI.const import LocalEventType
from myAI.hexmap.hex import HexOffset


# 生成我方算子死亡事件
# 根据observation先看看任务列表中的算子是不是还存活，如果算子死亡了，产生一个死亡事件
def genLocalEventOurDead(our_oprs, factionAI):
    localevent = {}
    our_oprs_id = [opr['obj_id'] for opr in our_oprs]
    for opr_id in factionAI.task.keys():
        if opr_id not in our_oprs_id:
            localevent[LocalEventType.OurDead] = opr_id
            return localevent
    return localevent



# 处理我方算子死亡事件
def handleLocalEventOurDead(obj_id, observation, factionAI):
    # 如果算子已死亡，则删除该算子对应的任务，并更新group_info中算子信息
    if obj_id in factionAI.task.keys():
        factionAI.task.pop(obj_id)
        factionAI.updateGroupOperators(obj_id)
        print(f'handle: dead obj_id = {obj_id} task = {factionAI.task.keys()}')

    # 如果是巡飞弹死亡，要考虑是否中断其所属战车的当前任务，给其下达巡飞弹下车的任务
    dead_opr = factionAI.get_ourbop_lastobservation(factionAI.lastobservation, obj_id)
    if dead_opr['sub_type'] == 7:
        # 得到巡飞弹所属战车算子
        cur_ifv_opr = factionAI.get_ourbop_observation(observation, dead_opr['launcher'])
        # 得到战车当前车上算子
        for passengerid in cur_ifv_opr['passenger_ids']:
            cur_passenger_opr = factionAI.get_ourbop_observation(observation, passengerid)
            # 如果还有一个巡飞弹
            if cur_passenger_opr['sub_type'] == 7:
                # 并且战车目前没有任务，则给战车下达巡飞弹下车的任务
                if cur_ifv_opr['obj_id'] not in factionAI.task.keys():
                    factionAI.task[cur_ifv_opr['obj_id']] = ['unload', passengerid]
                # 战车当前有任务，需要考虑当前任务和态势决定是否中断
                else:
                    factionAI.task[cur_ifv_opr['obj_id']] = ['unload', passengerid]
                break
    # 如果是战车死亡，
    # 已下车的情况，1.人员还可以继续控制，lose control字段为0，其任务不用删除；2.无人车不能继续控制了，lose control字段为1，其任务要删除；3.巡飞弹不能继续控制，同时死亡，其任务要删除
    # 未下车的情况，1.人员死亡；2.无人车失去控制；3.巡飞弹死亡，都要讲任务清除
    elif dead_opr['sub_type'] == 1:
        all_id = factionAI.get_allid_ifv(dead_opr)
        for pid in all_id:
            if pid in factionAI.task.keys():
                bop = factionAI.get_ourbop_lastobservation(factionAI.lastobservation, pid)
                if bop['on_board'] == 1:
                    factionAI.task.pop(pid)
                    factionAI.updateGroupOperators(pid)
                else:
                    if bop['sub_type'] == 2:
                        pass
                    else:
                        factionAI.task.pop(pid)
                        factionAI.updateGroupOperators(pid)
                print(f'handle: passenger dead obj_id = {pid} task = {factionAI.task.keys()}')

########################################################################################################################
# 生成己方算子下车事件
def genLocalEventGetOff(our_oprs, factionAI):
    localevent = {}
    for opr in our_oprs:
        if (opr['sub_type'] == 2 or opr['sub_type'] == 7) and opr['on_board'] == 0:
            before_opr = factionAI.get_ourbop_lastobservation(factionAI.lastobservation, opr['obj_id'])
            if before_opr['on_board'] == 1:
                localevent[LocalEventType.OurGetOff] = opr
                # 避免重复生成同一事件
                before_opr['on_board'] = opr['on_board']
                return localevent
    return localevent


# 处理己方算子下车事件
def handleLocalEventGetOff(operator, observation, factionAI):
    # 需要确定战车没有运输任务时才能战车分配相关任务
    # 可以在战车的unload任务执行完成后再分配新的任务
    for opr in observation['operators']:
        if opr['color'] == factionAI.color and opr['sub_type'] == 1:
            if opr['obj_id'] == operator['launcher']:
                # factionAI.allocate_ifv_task(opr)
                break


########################################################################################################################

#算子被打击事件
def genLocalEventShooted(observation, factionAI):
    localevent = {}
    if observation['judge_info']:
        enemiesIDs = factionAI.getEnemiesIDs()
        for judge_info in observation['judge_info']:
            # 如果打击方是敌方,则产生己方被打击事件
            if judge_info['att_obj_id'] in enemiesIDs:
                localevent[LocalEventType.OurShooted] = judge_info
            # 否则打击方是我方，则产生敌方被打击事件
            else:
                localevent[LocalEventType.EnemyShooted] = judge_info
            # 避免重复生成同一事件
            observation['judge_info'].remove(judge_info)
            return localevent
    return localevent

# 处理算子被打击事件
# 我方算子被打击事件
# def handleLocalEventOurShooted(judge_info, observation, factionAI):
#     # 判断我方算子是否死亡
#     last_our_opr = factionAI.get_ourbop_lastobservation(judge_info['target_obj_id'])
#     if judge_info['damage'] >= last_our_opr['blood']:
#         print('our obj_id:%s  is DEAD !' % (judge_info['target_obj_id']))
#         # 清除死亡算子的相关任务
#         if judge_info['target_obj_id'] in factionAI.task.keys():
#             factionAI.task.pop(judge_info['target_obj_id'])
#         # 更新group_info中算子信息
#         factionAI.updateGroupOperators(judge_info['target_obj_id'])

    # 从裁决信息中判断，推断敌方位置
    # area = []
    # for opr in observation['operators']:
    #     if opr['color'] == factionAI.color:
    #         if opr['obj_id'] == judge_info['target_obj_id']:
    #             #被打击算子能够直接看到打击者
    #             if judge_info['att_obj_id'] in opr['see_enemy_bop_ids']:
    #                 pass
    #             #无法看到时，需要推断
    #             else:
    #                 our_opr_hex = HexOffset(opr['cur_hex'] // 100, opr['cur_hex'] % 100)
    #                 # range_hex = our_opr_hex.get_arc(judge_info['distance'], [0,1,2,3,4,5])  # 半径为射击距离上的圆弧
    #                 for d in range(6):
    #                     range_hex = our_opr_hex.get_arc(judge_info['distance'], d)
    #                     range_hex += range_hex
    #                 for hex in range_hex:
    #                     area.append(hex.row * 100 + hex.col)
    #                 # 可进一步根据我方算子当前视野，缩小射击敌方算子所在位置
    #                 # if 射击敌方算子不在我方算子当前视野内
    #                 #     推断敌方可能位置，更新敌方算子信息列表
    #             return area

# 敌方算子被打击事件
def handleLocalEventEnemyShooted(judge_info, observation, factionAI):
    # 判断敌算子是否死亡,更新敌方算子信息列表
    last_enemy_opr = factionAI.get_enemybop_lastobservation(factionAI.lastobservation,judge_info['target_obj_id'])
    if judge_info['damage'] >= last_enemy_opr['blood']:
        print('enemy obj_id:%s  is DEAD !' % (judge_info['target_obj_id']))
        for enemy_info in factionAI.enemies:
            if enemy_info['obj_id'] == judge_info['target_obj_id']:
                factionAI.enemies.remove(enemy_info)
                break





########################################################################################################################


# 生成算子夺控事件
def genLocalEventOccupy(observation, factionAI):
    localevent = {}
    # 当lastobservation不为空时，即不是刚开局时
    if factionAI.lastobservation:
        # 根据lastobservationhe observation判断cities的flag状态，产生己方或敌方夺控事件
        cities1 = factionAI.lastobservation['cities']
        cities2 = observation['cities']
        for c1 in cities1:
            for c2 in cities2:
                # 如果前后两个状态中同一个夺控点的状态发生了改变
                if c1['coord'] == c2['coord'] and c1['flag'] != c2['flag']:
                    # 如果夺控点标志改为己方标志，则产生己方夺控事件
                    if c2['flag'] == factionAI.color:
                        localevent[LocalEventType.OurOccupy] = c2
                    # 否则产生敌方夺控事件
                    else:
                        localevent[LocalEventType.EnemyOccupy] = c2
                    # 避免重复生成该事件
                    c1['flag'] = c2['flag']
                    return localevent
    return localevent

# 处理算子夺控事件
def handleLocalEventOurOccupy(occupied_city, observation, factionAI):
    # 由于夺控任务执行完成后也会产生任务完成事件，在那里可以对算子进行新的任务分配
    # 这里仅更新夺控点相关状态，不对算子分配新的任务

    # for city in factionAI.lastobservation['cities']:
    #     if city['coord'] == occupied_city['coord']:
    #         # 避免重复生成该事件
    #         city['flag'] = occupied_city['flag']

    # 更新分组任务中目标状态（夺控点）
    factionAI.updateGroupCityFlag(observation)

def handleLocalEventEnemyOccupy(occupied_city, observation, factionAI):
    # for city in factionAI.lastobservation['cities']:
    #     if city['coord'] == occupied_city['coord']:
    #         # 避免重复生成该事件
    #         city['flag'] = occupied_city['flag']

    # 更新分组任务中目标状态（夺控点）
    factionAI.updateGroupCityFlag(observation)

    # 该夺控点周围一定有敌方算子，可以给己方算子分配侦查任务
    area = []
    city_hex = HexOffset(occupied_city['coord'] // 100, occupied_city['coord'] % 100)
    range_hex = city_hex.get_range(r=3)
    for hex in range_hex:
        area.append(hex.row * 100 + hex.col)
    return area


########################################################################################################################

# 生成任务状态事件
def genLocalEventTaskState(factionAI):
    # 根据task判断当前任务的状态，产生不同的任务状态事件
    localevent = {}
    for obj_id in factionAI.task.keys():
        # 如果任务成功完成，产生任务完成事件
        if factionAI.task[obj_id][0] == 'Success':
            localevent[LocalEventType.TaskCompleted] = obj_id
            return localevent
        # 如果任务执行失败，产生任务失败事件
        elif factionAI.task[obj_id][0] == 'Failure':
            localevent[LocalEventType.TaskFailed] = obj_id
            return localevent
        # 任务线程报错，产生线程错误事件
        elif factionAI.task[obj_id][0] == 'Error':
            localevent[LocalEventType.ThreadError] = obj_id
        # 其他情况，说明任务正在执行中，产生任务执行中事件
        else:
            pass
    return localevent

# 处理任务状态事件
# 处理任务完成事件
def handleLocalEventTaskCompleted(obj_id, observation, factionAI):
    for bop in observation['operators']:
        if obj_id == bop['obj_id']:
            # 如果为坦克，以最近看见的敌方算子所在方向进行侦查
            if bop['sub_type'] == 0:
                factionAI.allocate_tank_task(bop)
                # factionAI.allocate_task(obj_id)
            elif bop['sub_type'] == 1:
                factionAI.allocate_ifv_task(bop, observation)
                # factionAI.task.pop(obj_id)
            else:
                factionAI.allocate_task(obj_id)
            print(f'handle: reallocate obj_id = {obj_id} task = {factionAI.task[obj_id]}')
            break

# 处理任务失败事件
def handleLocalEventTaskFailed(obj_id, factionAI):
    factionAI.allocate_task(obj_id)

# 处理线程出错事件
def handleLocalEventThreadError(obj_id, factionAI):
    factionAI.allocate_task(obj_id)

########################################################################################################################